package com.xp.tinyurl.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xp.tinyurl.admin.dto.TinyUrlQueryDTO;
import com.xp.tinyurl.common.cache.LongUrlCache;
import com.xp.tinyurl.common.cache.ShortUrlCache;
import com.xp.tinyurl.common.dto.UShorterUrlDTO;
import com.xp.tinyurl.common.enums.ExpiredEnum;
import com.xp.tinyurl.common.utils.ExpiredEnumUtil;
import com.xp.tinyurl.common.utils.SnowflakeIdWorker;
import com.xp.tinyurl.dao.ShortUrlMapDao;
import com.xp.tinyurl.model.Channel;
import com.xp.tinyurl.model.ShortUrlMap;
import com.xp.tinyurl.service.thirdprovider.vo.UpushShorterUrlResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Service
public class ShortUrlMapSddlService {

    @Autowired
    private ShortUrlMapDao shortUrlMapDao;

    @Autowired
    private LongUrlCache longUrlCache;

    @Autowired
    private ShortUrlCache shortUrlCache;

    @Autowired
    private ChannelService channelService;

    @Autowired
    private ShortUrlGenerator shortUrlGenerator;

    @Resource
    private RedisTemplate redisTemplate;

    public void save(ShortUrlMap shortUrlMap) {
        shortUrlMap.setId(SnowflakeIdWorker.generateId());
        shortUrlMap.setAccessCount(0L);
        shortUrlMapDao.insert(shortUrlMap);
        longUrlCache.add(shortUrlMap.getLongUrl(), shortUrlMap);
    }

    public void updateExpireTime(ShortUrlMap shortUrlMap, ExpiredEnum expiredEnum){
        shortUrlMap.setExpireTime(ExpiredEnumUtil.toDate(expiredEnum));
        shortUrlMapDao.updateByPrimaryKeySelective(shortUrlMap);
    }

    @Transactional
    public void updateLongUrl(ShortUrlMap shortUrlMap, String longUrl){
        shortUrlMap.setLongUrl(longUrl);
        shortUrlMapDao.updateByPrimaryKeySelective(shortUrlMap);
    }


    /**
     * 创建短连接
     * @param shorterUrlDTO
     * @return
     */
    public ShortUrlMap createTinyUrl(UShorterUrlDTO shorterUrlDTO){
        //获取对应通道的域名
        Channel channel = channelService.getById(shorterUrlDTO.getChannelId());
        String mainDomainName = channel.getMainDomainName();
        //生成短连接
        UpushShorterUrlResult shorterUrlResult = shortUrlGenerator.generate(mainDomainName);
        //生成失败
        if (!shorterUrlResult.isSuccess()) {
            return null;
        }
        //成功 构建入库对象
        ShortUrlMap shortUrlMap = buildShortUrlMap(shorterUrlDTO, shorterUrlResult, mainDomainName);
        this.save(shortUrlMap);
        return shortUrlMap;
    }

    /**
     * 构建短URL信息对象
     * @param shorterUrlDTO
     * @param shorterUrlResult
     * @param mainDomainName
     * @return
     */
    private ShortUrlMap buildShortUrlMap(UShorterUrlDTO shorterUrlDTO, UpushShorterUrlResult shorterUrlResult, String mainDomainName) {
        ShortUrlMap shortUrlMap = new ShortUrlMap();
        shortUrlMap.setBusinessLine(shorterUrlDTO.getBusinessLine());
        shortUrlMap.setUuid(shorterUrlResult.getUuid());
        shortUrlMap.setShortUrl(mainDomainName + shorterUrlResult.getShortUrl());
        shortUrlMap.setLongUrl(shorterUrlDTO.getLongUrl());
        shortUrlMap.setCreateTime(new Date());
        // sddl不支持LocalDateTime写入
        shortUrlMap.setExpireTime(ExpiredEnumUtil.toDate(ExpiredEnum.getByCode(shorterUrlDTO.getExpired())));
        return shortUrlMap;
    }


    public PageInfo<ShortUrlMap> pageList(TinyUrlQueryDTO tinyUrlQueryDTO){
        Example example = new Example(ShortUrlMap.class);
        Example.Criteria criteria = example.createCriteria();
        if(!StringUtils.isEmpty(tinyUrlQueryDTO.getUuid())){
            criteria.andEqualTo("uuid", tinyUrlQueryDTO.getUuid());
        }
        example.setOrderByClause(" id desc");
        PageHelper.startPage(tinyUrlQueryDTO.getPageNo(), tinyUrlQueryDTO.getPageSize());
        List list = shortUrlMapDao.selectByExample(example);
        return new PageInfo(list);
    }

    /**
     * 根据短链以及过期时间 获取可用短链
     * @param uuid
     * @return
     */
    public ShortUrlMap getActiveByShortUrl(long uuid){
        Example example = new Example(ShortUrlMap.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("uuid",uuid);
        criteria.andGreaterThan("expireTime",new Date());
        List<ShortUrlMap> list = shortUrlMapDao.selectByExample(example);
        return CollectionUtils.isEmpty(list) ? null : list.get(0);
    }

    /**
     * 根据短链以及过期时间 获取可用短链
     * @param uuid
     * @return
     */
    public ShortUrlMap getByShortUrl(long uuid){
        Example example = new Example(ShortUrlMap.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("uuid",uuid);
        List<ShortUrlMap> list = shortUrlMapDao.selectByExample(example);
        return CollectionUtils.isEmpty(list) ? null : list.get(0);
    }

    /**
     * 根据短连接获取真实地址
     * @param uuid
     * @return
     */
    public ShortUrlMap getLongUrlByShortUrl4Query(long uuid) {
        //cache
        ShortUrlMap shortUrlMap = shortUrlCache.getLongUrl(uuid);
        //db
        if(shortUrlMap == null){
            shortUrlMap = getActiveByShortUrl(uuid);
        }
        if(shortUrlMap == null){
            return null;
        }
        if (!isShortUrlCurrentActive(shortUrlMap)) {
            this.delByShortUrl(uuid);
            shortUrlCache.remove(uuid);
            return null;
        }
        shortUrlCache.add(uuid+"", shortUrlMap);
        return shortUrlMap;
    }

    private boolean isShortUrlCurrentActive(ShortUrlMap shortUrlMap) {
        return shortUrlMap.getExpireTime().after(new Date());
    }

    public void delByShortUrl(long uuid){
        Example example = new Example(ShortUrlMap.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("uuid",uuid);
        shortUrlMapDao.deleteByExample(example);
    }


}
